#include "MainPalette.h"
#include "Block.h"
USING_NS_CC;

#define	RAND_LIMIT	32767
/// Random floating point number in range [lo, hi]
inline float RandomFloat(float lo, float hi)
{
	float r = (float)(std::rand() & (RAND_LIMIT));
	r /= RAND_LIMIT;
	r = (hi - lo) * r + lo;
	return r;
}

inline int RandomInt(int lo, int hi)
{
	return RandomFloat(lo, hi + 0.99999f);
}

inline int RandomIntExclude(int lo, int hi, int exclude)
{
	int ret = RandomInt(lo, hi);

	while( ret == exclude )
	{
		ret = RandomInt(lo, hi);
	}

	return ret;
}

// #define BLOCK_SIZE 59.2f
// #define BLOCK_STARTX 40.0f
// #define BLOCK_STARTY 65.0f

CMainPalette::CMainPalette( cocos2d::CCLayer* father, SPaletteFrame& frame ):
	m_pFather(father),
	m_frontPalette(NULL),
	BLOCK_NUM(frame.BLOCK_NUM),
	BLOCK_SIZE(frame.BLOCK_SIZE),
	BLOCK_STARTX(frame.BLOCK_STARTX),
	BLOCK_STARTY(frame.BLOCK_STARTY),
	FRONTPALETTE_IMAGE(frame.FRONTPALETTE_IMAGE)


// 	BLOCK_NUM(4),
// 	BLOCK_SIZE(74.f),
// 	BLOCK_STARTX(14),
// 	BLOCK_STARTY(35.0f),
// 	FRONTPALETTE_IMAGE("Images\\Palette\\plt4x4.png")
{
	
}

CMainPalette::~CMainPalette()
{

}

void CMainPalette::init()
{
	std::srand( timeGetTime() );

	// create 5x5 palette front frame
	m_frontPalette = CCSprite::spriteWithFile(FRONTPALETTE_IMAGE);

	CCSize size = CCDirector::sharedDirector()->getWinSize();
	// position the sprite on the center of the screen
	m_frontPalette->setPosition( ccp(size.width/2, size.height/2) );

	// add the sprite as a child to this layer
	m_pFather->addChild(m_frontPalette, 0);

	// create 5x5 blocks
	m_blocks = new CBlock[BLOCK_NUM*BLOCK_NUM];
	for (int i=0; i < BLOCK_NUM; ++i)
	{
		for (int j=0; j < BLOCK_NUM; ++j)
		{
			CBlock* pBlock = &(m_blocks[i*BLOCK_NUM + j]);

			pBlock->BlockSize(BLOCK_SIZE);
			
			pBlock->init();
			pBlock->setPos(ccp(BLOCK_STARTX + BLOCK_SIZE * 0.5f + i * BLOCK_SIZE, BLOCK_STARTY + BLOCK_SIZE * 0.5f + j * BLOCK_SIZE));

			pBlock->changeColor( (EBlk_Color)RandomInt(2,6) );						
		}
	}
	//throw std::exception("The method or operation is not implemented.");
}

//////////////////////////////////////////////////////////////////////////
void CMainPalette::restart()
{
	for (int i=0; i < BLOCK_NUM; ++i)
	{
		for (int j=0; j < BLOCK_NUM; ++j)
		{
			CBlock* pBlock = &(m_blocks[i*BLOCK_NUM + j]);
			pBlock->changeColor( (EBlk_Color)RandomInt(2,6) );						
		}
	}
	//throw std::exception("The method or operation is not implemented.");
}

void CMainPalette::destroy()
{
	//throw std::exception("The method or operation is not implemented.");
}

void CMainPalette::display()
{
	m_frontPalette->setIsVisible(true);

	for (int i=0; i < BLOCK_NUM * BLOCK_NUM; ++i)
	{
		CBlock* pBlock = &(m_blocks[i]);
		pBlock->display();
	}
	//throw std::exception("The method or operation is not implemented.");
}

void CMainPalette::hide()
{
	//throw std::exception("The method or operation is not implemented.");
	m_frontPalette->setIsVisible(false);

	for (int i=0; i <  BLOCK_NUM * BLOCK_NUM; ++i)
	{
		CBlock* pBlock = &(m_blocks[i]);
		pBlock->hide();
	}
}

int CMainPalette::getBlockIndex( const cocos2d::CCPoint& point )
{
	int indexX = (int)((point.x - BLOCK_STARTX) / BLOCK_SIZE );
	int indexY = (int)((point.y - BLOCK_STARTY) / BLOCK_SIZE );

	if (indexX < 0 || indexX > BLOCK_NUM - 1 || indexY < 0 || indexY > BLOCK_NUM - 1 )
	{
		// out of range, not a valid execute
		return -1;
	}

	return (indexX *  BLOCK_NUM + indexY);
}

//////////////////////////////////////////////////////////////////////////
void CMainPalette::execute( const cocos2d::CCPoint& start, const cocos2d::CCPoint& end )
{
	// convert point to block index
	// fast cast
	int indexStart = getBlockIndex(start);
	int indexStop = getBlockIndex(end);

	if ( indexStart == -1 || indexStop == -1 )
	{
		return;
	}

	if (indexStart == indexStop)
	{
		return;
	}

	//////////////////////////////////////////////////////////////////////////
	// execute block

	// judge the less & large
	int lessColor = m_blocks[indexStart].Color() > m_blocks[indexStop].Color() ? m_blocks[indexStop].Color() : m_blocks[indexStart].Color();
	int largeColor = m_blocks[indexStart].Color() > m_blocks[indexStop].Color() ? m_blocks[indexStart].Color() : m_blocks[indexStop].Color();

	// try merge
	int mergeResult = lessColor + largeColor;


	// judge merge or dissove
	int operation = 0;

	if ( mergeResult == 9 )
	{
		operation = -1;
	}
	else if ( mergeResult >= 5 && mergeResult <= 7 )
	{
		operation = 1;

		// if merging == 7, may merge or dissove
		if ( mergeResult == 7 )
		{
			if (m_blocks[indexStart].Color() == eBC_Red || m_blocks[indexStop].Color() == eBC_Red)
			{
				operation = 0;
			}
		}
	}






	if (operation == 1)
	{
		// merging, into two same merged color
		m_blocks[indexStart].changeColor(mergeResult);
		m_blocks[indexStop].changeColor(mergeResult);
	}
	else if ( operation == -1)
	{
		// dissove, random color but not the original
		float color = RandomFloat(2.0f, 5.0f);
		m_blocks[indexStart].changeColor(RandomIntExclude(2,4,lessColor));
		color = RandomFloat(2.0f, 5.0f);
		m_blocks[indexStop].changeColor(RandomIntExclude(2,4,lessColor));
	}

	// finish executing
	//////////////////////////////////////////////////////////////////////////



	//throw std::exception("The method or operation is not implemented.");
}


